/*
 * Copyright (C) 2004-2005, Universidade Federal de Campina Grande. All rights reserved.
 */
package org.epanetgrid.otimizacao.ag;

import java.util.Arrays;
import java.util.List;

import org.epanetgrid.otimizacao.util.OtimizacaoUtil;
import org.jheuristics.Individual;
import org.jheuristics.ga.GAConfig;
import org.jheuristics.ga.GAStatus;
import org.jheuristics.ga.operators.Probability;
import org.jheuristics.ga.operators.Reproductor;
import org.jheuristics.util.BitString;
import org.jheuristics.util.RandomGenerator;


/**
 *	Efetua muta��o baseada no ponto de erro do cromossomo (ver especifica��es para maior detalhe)
 * @author Marcell Manfrin, marcell at ourgrid.org, 2005
 */
public class MutacaoDirecionadaEsther extends MutacaoNormal {

	/**
	 *
	 * @param probability Probabilidade de muta��o
	 * @param maximoDeTentativasInvalidas N�mero m�ximo de tentativas
	 * @param porcentagemDeMutacao Porcentagem de bombas que sofrer�o muta��o
	 */
	public MutacaoDirecionadaEsther(Probability probability, int maximoDeTentativasInvalidas, double porcentagemDeMutacao) {
		super(probability, maximoDeTentativasInvalidas, porcentagemDeMutacao);
	}

	/**
	 * @param decoretedReproductor Reprodutor
	 * @param probability Probabilidade de muta��o
	 * @param maximoDeTentativasInvalidas N�mero m�ximo de tentativas
	 * @param porcentagemDeMutacao Porcentagem de bombas que sofrer�o muta��o
	 */
	public MutacaoDirecionadaEsther(Reproductor decoretedReproductor, Probability probability, int maximoDeTentativasInvalidas, double porcentagemDeMutacao) {
		super(decoretedReproductor, probability, maximoDeTentativasInvalidas, porcentagemDeMutacao);
	}

	public Individual[] reproduce(Individual[] parents, GAStatus status, GAConfig config) {
		Individual[] result = super.reproduce(parents, status, config);
		if (null != getDecoratedReproductor()) {
			result = getDecoratedReproductor().reproduce(result, status, config);
		}
		return result;
	}

	
	/* 
	 * Ver especifica��o
	 * (non-Javadoc)
	 * @see org.jheuristics.ga.operators.reproductors.AbstractMutation#mutate(org.jheuristics.Individual, org.jheuristics.ga.GAStatus, org.jheuristics.ga.GAConfig)
	 */
	protected Individual mutate(Individual parent, GAStatus status, GAConfig config) {
		SimpleFitness fitness = (SimpleFitness) parent.getFitness();
		List gens = (List) parent.getGens();
		RandomGenerator random = config.getRandomGenerator();
		int posicao = fitness.getIntervaloDeErro();
		if (/*-1 !=*/ 0 < posicao) {
			
			StringBuffer buffer = new StringBuffer();
			buffer.append("\nCromossomo enviado para Mutação Direcionada: ");
			buffer.append(OtimizacaoUtil.format(parent));
			buffer.append("\n");
			buffer.append("Ponto de mutação: ");
			buffer.append(posicao);
			logger.debug(buffer);
			
			posicao -= 1;
			
			if(posicao >= gens.size()) {
				return null;
			}
			
			BitString genOrignal = (BitString) gens.get(posicao);
			BitString genMutado = mutate(new BitString(genOrignal), random);
			
			buffer = new StringBuffer();
			if (!genOrignal.equals(genMutado)) {
				List<BitString> genesMutados = Arrays.asList(montagemDosGenes(gens, genMutado, posicao));
				buffer.append("Cromossomo mutado: ");
				buffer.append(OtimizacaoUtil.gensToString(genesMutados));
				buffer.append("\n");
				logger.debug(buffer);
				return config.getIndividualsFactory().createSpecificIndividual(genesMutados, config);
			}
			logger.debug(buffer);
		}
		return null;
	}

}
